package eu.hellek.gba.server.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.beoui.geocell.GeocellUtils;
import com.beoui.geocell.model.BoundingBox;
import com.google.appengine.api.datastore.GeoPt;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.googlecode.objectify.Objectify;
import eu.hellek.gba.model.Line;
import eu.hellek.gba.model.Point;
import eu.hellek.gba.server.dao.Dao;
import eu.hellek.gba.shared.LineProxy;
public class Utils {
public static final int geoCellResolution = 8;
public static final int distanceMultiplikator = 100000;
/*public static final float searchDistanceWE = 0.00580F; // about 500m each
public static final float searchDistanceNS = 0.00478F;*/
public static final float searchDistanceWE = 0.00870F; // about 750m each
public static final float searchDistanceNS = 0.00717F;
private static Set<String> allowedUsers = new HashSet<String>();
static {
allowedUsers.add("todo");
}
public static GeoPt vectorBetween(Point a, Point b) {
GeoPt res = new GeoPt(a.getLatlon().getLatitude()-b.getLatlon().getLatitude(),a.getLatlon().getLongitude()-b.getLatlon().getLongitude());
return res;
}
private static GeoPt vectorBetween(GeoPt a, Point b) {
GeoPt res = new GeoPt(a.getLatitude()-b.getLatlon().getLatitude(),a.getLongitude()-b.getLatlon().getLongitude());
return res;
}
public static double distanceApprox(double a, double b) {
return Math.sqrt(Math.pow(a, 2)+ Math.pow(b, 2));
}
public static double distanceApprox(Point a, Point b) {
GeoPt pt = vectorBetween(a, b);
return distanceApprox(pt.getLatitude(), pt.getLongitude());
}
private static double distanceApprox(GeoPt a, Point b) {
GeoPt pt = vectorBetween(a, b);
return distanceApprox(pt.getLatitude(), pt.getLongitude());
}
public static double distanceInMeters(Point a, Point b) {
com.beoui.geocell.model.Point p1 = new com.beoui.geocell.model.Point(a.getLatlon().getLatitude(),a.getLatlon().getLongitude());
com.beoui.geocell.model.Point p2 = new com.beoui.geocell.model.Point(b.getLatlon().getLatitude(),b.getLatlon().getLongitude());
return GeocellUtils.distance(p1, p2);
}
public static User getUser() {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
return user;
}
public static String computeGeoCell(com.beoui.geocell.model.Point p) {
return MyGeocellUtils.compute(p, Utils.geoCellResolution);
}
public static String computeGeoCell(Point p) {
return Utils.computeGeoCell(new com.beoui.geocell.model.Point(p.getLatlon().getLatitude(), p.getLatlon().getLongitude()));
}
public static void eMailError(Throwable e, String where) {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
String msgBody = "Error in " + where + ": " + e + "\n\n";
msgBody += e.getCause() + "\n\n";
StackTraceElement[] trace = e.getStackTrace();
for(StackTraceElement ele : trace) {
msgBody += ele.toString() + "\n";
}
try {
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("todo", "App Engine"));
msg.addRecipient(Message.RecipientType.TO, new InternetAddress("todo", "name"));
msg.setSubject("Error in " + where);
msg.setText(msgBody);
Transport.send(msg);
} catch(Exception exMail) {
exMail.printStackTrace();
}
}
public static void eMailGeneric(String text, String subject) {
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
String msgBody = text;
try {
Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("todo", "App Engine"));
msg.addRecipient(Message.RecipientType.TO, new InternetAddress("todo", "todo"));
msg.setSubject(subject);
msg.setText(msgBody);
Transport.send(msg);
} catch(Exception exMail) {
exMail.printStackTrace();
}
}
public static int distanceBetweenGeoCells(String cell1, String cell2) {
return distanceBetweenGeoCells(cell1, cell2, false);
}
public static int distanceBetweenGeoCells(String cell1, String cell2, boolean overWeighDiagonale) {
BoundingBox bb1 = MyGeocellUtils.computeBox(cell1);
BoundingBox bb2 = MyGeocellUtils.computeBox(cell2);
// com.beoui.geocell.model.Point p1 = bb1.getNorthEast();
// com.beoui.geocell.model.Point p2 = bb2.getNorthEast();
com.beoui.geocell.model.Point p1 = bb1.getSouthWest();
com.beoui.geocell.model.Point p2 = bb2.getSouthWest();
// System.out.println(p1.getLat() + ", " + p1.getLon());
// System.out.println(p2.getLat() + ", " + p2.getLon());
int dist1;
int dist2;
if(p1.getLat() >= p2.getLat() && p1.getLon() >= p2.getLon()) {
// p1 is north-east of p2 or at same height/length
com.beoui.geocell.model.Point p3 = new com.beoui.geocell.model.Point(p1.getLat(), p2.getLon());
String cell3 = computeGeoCell(p3);
dist1 = (MyGeocellUtils.interpolationCount(cell1, cell3)-1)*5;
dist2 = (MyGeocellUtils.interpolationCount(cell3, cell2)-1)*6;
// System.err.println(dist1 + " " + dist2);
} else if(p1.getLat() < p2.getLat() && p1.getLon() < p2.getLon()) {
// p1 is south-west of p2
com.beoui.geocell.model.Point p3 = new com.beoui.geocell.model.Point(p1.getLat(), p2.getLon());
String cell3 = computeGeoCell(p3);
dist1 = (MyGeocellUtils.interpolationCount(cell3, cell1)-1)*5;
dist2 = (MyGeocellUtils.interpolationCount(cell2, cell3)-1)*6;
// System.err.println(dist1 + " " + dist2);
} else if(p1.getLat() >= p2.getLat() && p1.getLon() < p2.getLon()) {
// p1 is north-west of p2
com.beoui.geocell.model.Point p3 = new com.beoui.geocell.model.Point(p1.getLat(), p2.getLon());
String cell3 = computeGeoCell(p3);
dist1 = (MyGeocellUtils.interpolationCount(cell3, cell1)-1)*5;
dist2 = (MyGeocellUtils.interpolationCount(cell3, cell2)-1)*6;
// System.err.println(dist1 + " " + dist2);
} else if(p1.getLat() < p2.getLat() && p1.getLon() >= p2.getLon()) {
// p1 is south-east of p2
com.beoui.geocell.model.Point p3 = new com.beoui.geocell.model.Point(p1.getLat(), p2.getLon());
String cell3 = computeGeoCell(p3);
dist1 = (MyGeocellUtils.interpolationCount(cell1, cell3)-1)*5;
dist2 = (MyGeocellUtils.interpolationCount(cell2, cell3)-1)*6;
// System.err.println(dist1 + " " + dist2);
} else {
System.err.println("Error in distanceBetweenGeoCells!!! Cells: " + cell1 + " and " + cell2);
return -1;
}
if(overWeighDiagonale) {
return (int)pythagorasOverWeighDiagonale(dist1, dist2);
} else {
return (int)pythagoras(dist1, dist2);
}
}
public static Point closestPoint(GeoPt thePoint, Collection<Point> points) {
GeoPt p = thePoint;
double dMin = 99999999.9;
Point pMin = null;
for(Point pCur : points) {
double distCur = Utils.distanceApprox(p, pCur);
if(pCur.isIgnore()) { // absolutely avoid points that are set as ignore. Related to the dirty hack that searches any point, if none were found that are not "ignore"-flagged. Theoretically there shouldn't be any case where this is necessary, but right now there is (rarely).
distCur += 10000;
}
if(distCur < dMin) {
dMin = distCur;
pMin = pCur;
}
}
return pMin;
}
public static double pythagoras(int a, int b) {
return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
}
public static double pythagorasOverWeighDiagonale(int a, int b) {
double res = pythagoras(a, b);
if(a != 0 && b != 0) {
res = res * 1.35;
}
return res;
}
/*
* Get the connection between two points of the same line. The index of the second point must be higher
* than the index of the first point
*/
public static LineProxy getConnection(Point p1, Point p2, Objectify ofy) {
Line line = Dao.getInstance().getLineByKey(p1.getOwner(), ofy);
List<Float> floats = new LinkedList<Float>();
floats.add(p1.getLatlon().getLatitude());
floats.add(p1.getLatlon().getLongitude());
double trackdist = 0.0;
Point lastpoint = p1;
Collection<Point> points = Dao.getInstance().getPointsToDisplayForLine(line, ofy);
for(Point ppt : points) {
if(ppt.getIndex() > p1.getIndex()) {
if(ppt.getIndex() < p2.getIndex()) {
floats.add(ppt.getLatlon().getLatitude());
floats.add(ppt.getLatlon().getLongitude());
trackdist += Utils.distanceInMeters(lastpoint, ppt);
lastpoint = ppt;
} else {
break;
}
}
}
floats.add(p2.getLatlon().getLatitude());
floats.add(p2.getLatlon().getLongitude());
trackdist += Utils.distanceInMeters(lastpoint, p2);
int trackdist_int = (int)Math.round(trackdist);
List<Float> coords = new ArrayList<Float>();
List<String> stations = null;
if(line.getType() >= 10) {
stations = new ArrayList<String>();
for(Point p : points) {
coords.add(p.getLatlon().getLatitude());
coords.add(p.getLatlon().getLongitude());
stations.add(p.getStreet());
}
} else {
for(Point p : points) {
coords.add(p.getLatlon().getLatitude());
coords.add(p.getLatlon().getLongitude());
}
}
int type;
if(line.getType() == 11) {
type = 2;
} else if(line.getType() == 21) {
type = 3;
} else if(line.getType() == 13) {
type = 4;
} else if(line.getType() == 15) {
type = 5;
} else {
type = 1;
}
LineProxy lp = new LineProxy(line.getId().toString(), line.getLinenum(), line.getRamal(), type, floats, trackdist_int, coords, stations);
lp.setStartStreet(p1.getStreet());
lp.setDestStreet(p2.getStreet());
return lp;
}
public static LineProxy walk(Point p1, Point p2) {
int walkingDistance = (int)Math.round(Utils.distanceInMeters(p1, p2));
List<Float> walkingPoints = new LinkedList<Float>();
walkingPoints.add(p1.getLatlon().getLatitude());
walkingPoints.add(p1.getLatlon().getLongitude());
walkingPoints.add(p2.getLatlon().getLatitude());
walkingPoints.add(p2.getLatlon().getLongitude());
return new LineProxy(null, "caminar", walkingDistance + "m", 0, walkingPoints, walkingDistance, walkingPoints);
}
public static boolean isUserInSpecialACL() {
User user = Utils.getUser();
if(user == null) {
return false;
} else if(user.getEmail() == null) {
return false;
} else {
String eMail = user.getEmail();
if(allowedUsers.contains(eMail)) {
return true;
} else {
return false;
}
}
}
}